package smallfrench.moteur.interp;

import java.util.ArrayList;

import smallfrench.moteur.biblio.BibliothequeStandard;
import smallfrench.moteur.interp.err.IntercepteurErreurs;
import smallfrench.moteur.lexer.Lexer;
import smallfrench.moteur.lexer.lexemes.Lexeme;
import smallfrench.moteur.noeuds.Noeud;
import smallfrench.moteur.parser.LecteurLexemes;
import smallfrench.moteur.parser.Parser;

/**
 * Permet d'interpreter un script.<br>
 * Tokenize, parse puis exécute.
 * 
 * @author antoine1023
 *
 */
public class Interpreteur extends EcoutableExcecution
implements EcouteurExecution {

	private final Lexer lexer = new Lexer();

	private IEntreeConsole entree;

	private ISortieConsole sortie;
	private ISortieConsole sortieErreur;

	private IntercepteurErreurs intercepteurErreurs;


	public Interpreteur(
			ISortieConsole sortie,
			ISortieConsole sortieErreur,
			IEntreeConsole entree,
			IntercepteurErreurs intercepteurErreurs) {

		setIntercepteurErreurs(intercepteurErreurs);
		this.sortie = sortie;
		this.sortieErreur = sortieErreur;
		this.entree = entree;
	}

	public void setIntercepteurErreurs(IntercepteurErreurs i) {
		i.verifierInterception(RuntimeException.class);
		intercepteurErreurs = i;
	}

	/**
	 * Evalue une expression.
	 * @param source
	 * @return Le {@link ProcessusScript} créé
	 */
	public ProcessusScript evaluer(String source) {

		try {

			ArrayList<Lexeme> tokens = lexer.analyser(source, false, false);

			LecteurLexemes lt = new LecteurLexemes(tokens);

			final ArrayList<Noeud> noeuds = Parser.parserProgramme(lt);

			final Portee portee = BibliothequeStandard.getBibliotheque();

			IListeInstructions intructions = new IListeInstructions() {
				@Override
				public Portee getPortee() {
					return portee;
				}

				@Override
				public Noeud[] getNoeuds() {
					return noeuds.toArray(new Noeud[noeuds.size()]);
				}
			};

			Tache tache = new Tache(intructions);

			ProcessusScript ps = new ProcessusScript(
					entree, sortie, sortieErreur,
					intercepteurErreurs,
					tache);

			ps.ajouterEcouteur(this);
			tache.start();
			return ps;

		} catch (Exception e) {
			intercepteurErreurs.obtenir(e.getClass()).intercepter(e);
		}

		return null;
	}

	@Override
	public void onFin(ProcessusScript processusScript) {
		signalerFin(processusScript);
	}
}
